package roaring

import (
	
	
	
	

	
)

type container interface {
	// addOffset returns the (low, high) parts of the shifted container.
	// Whenever one of them would be empty, nil will be returned instead to
	// avoid unnecessary allocations.
	addOffset(uint16) (container, container)

	clone() container
	and(container) container
	andCardinality(container) int
	iand(container) container // i stands for inplace
	andNot(container) container
	iandNot(container) container // i stands for inplace
	isEmpty() bool
	getCardinality() int
	// rank returns the number of integers that are
	// smaller or equal to x. rank(infinity) would be getCardinality().
	rank(uint16) int

	iadd(x uint16) bool                   // inplace, returns true if x was new.
	iaddReturnMinimized(uint16) container // may change return type to minimize storage.

	//addRange(start, final int) container  // range is [firstOfRange,lastOfRange) (unused)
	iaddRange(start, endx int) container // i stands for inplace, range is [firstOfRange,endx)

	iremove(x uint16) bool                   // inplace, returns true if x was present.
	iremoveReturnMinimized(uint16) container // may change return type to minimize storage.

	not(start, final int) container        // range is [firstOfRange,lastOfRange)
	inot(firstOfRange, endx int) container // i stands for inplace, range is [firstOfRange,endx)
	xor(r container) container
	getShortIterator() shortPeekable
	iterate(cb func(x uint16) bool) bool
	getReverseIterator() shortIterable
	getManyIterator() manyIterable
	contains(i uint16) bool
	maximum() uint16
	minimum() uint16

	// equals is now logical equals; it does not require the
	// same underlying container types, but compares across
	// any of the implementations.
	equals(r container) bool

	fillLeastSignificant16bits(array []uint32, i int, mask uint32) int
	or(r container) container
	orCardinality(r container) int
	isFull() bool
	ior(r container) container   // i stands for inplace
	intersects(r container) bool // whether the two containers intersect
	lazyOR(r container) container
	lazyIOR(r container) container
	getSizeInBytes() int
	//removeRange(start, final int) container  // range is [firstOfRange,lastOfRange) (unused)
	iremoveRange(start, final int) container // i stands for inplace, range is [firstOfRange,lastOfRange)
	selectInt(x uint16) int                  // selectInt returns the xth integer in the container
	serializedSizeInBytes() int
	writeTo(io.Writer) (int, error)

	numberOfRuns() int
	toEfficientContainer() container
	String() string
	containerType() contype
}

type contype uint8

const (
	bitmapContype contype = iota
	arrayContype
	run16Contype
	run32Contype
)

// careful: range is [firstOfRange,lastOfRange]
func rangeOfOnes(,  int) container {
	if  > MaxUint16 {
		panic("rangeOfOnes called with start > MaxUint16")
	}
	if  > MaxUint16 {
		panic("rangeOfOnes called with last > MaxUint16")
	}
	if  < 0 {
		panic("rangeOfOnes called with start < 0")
	}
	if  < 0 {
		panic("rangeOfOnes called with last < 0")
	}
	return newRunContainer16Range(uint16(), uint16())
}

type roaringArray struct {
	keys            []uint16
	containers      []container `msg:"-"` // don't try to serialize directly.
	needCopyOnWrite []bool
	copyOnWrite     bool
}

func newRoaringArray() *roaringArray {
	return &roaringArray{}
}

// runOptimize compresses the element containers to minimize space consumed.
// Q: how does this interact with copyOnWrite and needCopyOnWrite?
// A: since we aren't changing the logical content, just the representation,
//
//	we don't bother to check the needCopyOnWrite bits. We replace
//	(possibly all) elements of ra.containers in-place with space
//	optimized versions.
func ( *roaringArray) () {
	for  := range .containers {
		.containers[] = .containers[].toEfficientContainer()
	}
}

func ( *roaringArray) ( uint16,  container,  bool) {
	.keys = append(.keys, )
	.containers = append(.containers, )
	.needCopyOnWrite = append(.needCopyOnWrite, )
}

func ( *roaringArray) ( roaringArray,  int) {
	 := .needCopyOnWrite[]
	.appendContainer(.keys[], .containers[], )
}

func ( *roaringArray) ( roaringArray,  int) {
	// cow only if the two request it, or if we already have a lightweight copy
	 := (.copyOnWrite && .copyOnWrite) || .needsCopyOnWrite()
	if ! {
		// since there is no copy-on-write, we need to clone the container (this is important)
		.appendContainer(.keys[], .containers[].clone(), )
	} else {
		.appendContainer(.keys[], .containers[], )
		if !.needsCopyOnWrite() {
			.setNeedsCopyOnWrite()
		}
	}
}

func ( *roaringArray) ( roaringArray, ,  int) {
	for  := ;  < ; ++ {
		.appendWithoutCopy(, )
	}
}

func ( *roaringArray) ( roaringArray, ,  int) {
	for  := ;  < ; ++ {
		.appendCopy(, )
	}
}

func ( *roaringArray) ( roaringArray,  uint16) {
	// cow only if the two request it, or if we already have a lightweight copy
	 := .copyOnWrite && .copyOnWrite

	for  := 0;  < .size(); ++ {
		if .keys[] >=  {
			break
		}
		 :=  || .needsCopyOnWrite()
		if  {
			.appendContainer(.keys[], .containers[], )
			if !.needsCopyOnWrite() {
				.setNeedsCopyOnWrite()
			}

		} else {
			// since there is no copy-on-write, we need to clone the container (this is important)
			.appendContainer(.keys[], .containers[].clone(), )

		}
	}
}

func ( *roaringArray) ( roaringArray,  uint16) {
	// cow only if the two request it, or if we already have a lightweight copy
	 := .copyOnWrite && .copyOnWrite

	 := .getIndex()
	if  >= 0 {
		++
	} else {
		 = - - 1
	}

	for  := ;  < .size(); ++ {
		 :=  || .needsCopyOnWrite()
		if  {
			.appendContainer(.keys[], .containers[], )
			if !.needsCopyOnWrite() {
				.setNeedsCopyOnWrite()
			}
		} else {
			// since there is no copy-on-write, we need to clone the container (this is important)
			.appendContainer(.keys[], .containers[].clone(), )

		}
	}
}

func ( *roaringArray) (,  int) {
	if  <=  {
		return
	}

	 :=  - 

	copy(.keys[:], .keys[:])
	copy(.containers[:], .containers[:])
	copy(.needCopyOnWrite[:], .needCopyOnWrite[:])

	.resize(len(.keys) - )
}

func ( *roaringArray) ( int) {
	for  := ;  < len(.containers); ++ {
		.containers[] = nil
	}

	.keys = .keys[:]
	.containers = .containers[:]
	.needCopyOnWrite = .needCopyOnWrite[:]
}

func ( *roaringArray) () {
	.resize(0)
	.copyOnWrite = false
}

func ( *roaringArray) () *roaringArray {

	 := roaringArray{}
	.copyOnWrite = .copyOnWrite

	// this is where copyOnWrite is used.
	if .copyOnWrite {
		.keys = make([]uint16, len(.keys))
		copy(.keys, .keys)
		.containers = make([]container, len(.containers))
		copy(.containers, .containers)
		.needCopyOnWrite = make([]bool, len(.needCopyOnWrite))

		.markAllAsNeedingCopyOnWrite()
		.markAllAsNeedingCopyOnWrite()

		// sa.needCopyOnWrite is shared
	} else {
		// make a full copy

		.keys = make([]uint16, len(.keys))
		copy(.keys, .keys)

		.containers = make([]container, len(.containers))
		for  := range .containers {
			.containers[] = .containers[].clone()
		}

		.needCopyOnWrite = make([]bool, len(.needCopyOnWrite))
	}
	return &
}

// clone all containers which have needCopyOnWrite set to true
// This can be used to make sure it is safe to munmap a []byte
// that the roaring array may still have a reference to.
func ( *roaringArray) () {
	for ,  := range .needCopyOnWrite {
		if  {
			.containers[] = .containers[].clone()
			.needCopyOnWrite[] = false
		}
	}
}

// unused function:
//func (ra *roaringArray) containsKey(x uint16) bool {
//	return (ra.binarySearch(0, int64(len(ra.keys)), x) >= 0)
//}

func ( *roaringArray) ( uint16) container {
	 := .binarySearch(0, int64(len(.keys)), )
	if  < 0 {
		return nil
	}
	return .containers[]
}

func ( *roaringArray) ( int) container {
	return .containers[]
}

func ( *roaringArray) ( int,  bool) container {
	 := .getContainerAtIndex()
	switch t := .(type) {
	case *arrayContainer:
		 = .toBitmapContainer()
	case *runContainer16:
		if !.isFull() {
			 = .toBitmapContainer()
		}
	case *bitmapContainer:
		if  && .needCopyOnWrite[] {
			 = .containers[].clone()
		}
	}
	return 
}

// getUnionedWritableContainer switches behavior for in-place Or
// depending on whether the container requires a copy on write.
// If it does using the non-inplace or() method leads to fewer allocations.
func ( *roaringArray) ( int,  container) container {
	if .needCopyOnWrite[] {
		return .getContainerAtIndex().or()
	}
	return .getContainerAtIndex().ior()

}

func ( *roaringArray) ( int) container {
	if .needCopyOnWrite[] {
		.containers[] = .containers[].clone()
		.needCopyOnWrite[] = false
	}
	return .containers[]
}

func ( *roaringArray) ( uint16) int {
	// before the binary search, we optimize for frequent cases
	 := len(.keys)
	if ( == 0) || (.keys[-1] == ) {
		return  - 1
	}
	return .binarySearch(0, int64(), )
}

func ( *roaringArray) ( int) uint16 {
	return .keys[]
}

func ( *roaringArray) ( int,  uint16,  container) {
	.keys = append(.keys, 0)
	.containers = append(.containers, nil)

	copy(.keys[+1:], .keys[:])
	copy(.containers[+1:], .containers[:])

	.keys[] = 
	.containers[] = 

	.needCopyOnWrite = append(.needCopyOnWrite, false)
	copy(.needCopyOnWrite[+1:], .needCopyOnWrite[:])
	.needCopyOnWrite[] = false
}

func ( *roaringArray) ( uint16) bool {
	 := .binarySearch(0, int64(len(.keys)), )
	if  >= 0 { // if a new key
		.removeAtIndex()
		return true
	}
	return false
}

func ( *roaringArray) ( int) {
	copy(.keys[:], .keys[+1:])
	copy(.containers[:], .containers[+1:])

	copy(.needCopyOnWrite[:], .needCopyOnWrite[+1:])

	.resize(len(.keys) - 1)
}

func ( *roaringArray) ( int,  container) {
	.containers[] = 
}

func ( *roaringArray) ( int,  uint16,  container,  bool) {
	.keys[] = 
	.containers[] = 
	.needCopyOnWrite[] = 
}

func ( *roaringArray) () int {
	return len(.keys)
}

func ( *roaringArray) (,  int64,  uint16) int {
	 := 
	 :=  - 1
	for +16 <=  {
		 :=  + (-)/2 // avoid overflow
		 := .keys[]

		if  <  {
			 =  + 1
		} else if  >  {
			 =  - 1
		} else {
			return int()
		}
	}
	for ;  <= ; ++ {
		 := .keys[]
		if  >=  {
			if  ==  {
				return int()
			}
			break
		}
	}
	return -int( + 1)
}

func ( *roaringArray) ( interface{}) bool {
	,  := .(roaringArray)
	if  {

		if .size() != .size() {
			return false
		}
		for ,  := range .keys {
			if  != .keys[] {
				return false
			}
		}

		for ,  := range .containers {
			if !.equals(.containers[]) {
				return false
			}
		}
		return true
	}
	return false
}

func ( *roaringArray) () uint64 {
	 := uint64(len(.keys))
	if .hasRunCompression() {
		if  < noOffsetThreshold { // for small bitmaps, we omit the offsets
			return 4 + (+7)/8 + 4*
		}
		return 4 + (+7)/8 + 8* // - 4 because we pack the size with the cookie
	}
	return 4 + 4 + 8*

}

// should be dirt cheap
func ( *roaringArray) () uint64 {
	 := .headerSize()
	for ,  := range .containers {
		 += uint64(.serializedSizeInBytes())
	}
	return 
}

// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
func ( *roaringArray) ( io.Writer) ( int64,  error) {
	 := .hasRunCompression()
	 := 0
	 := 8
	if  {
		 = 4
		 = (len(.keys) + 7) / 8
	}
	 := 4 * len(.keys)
	 :=  +  + 

	 := make([]byte, +4*len(.keys))

	 := 0

	if  {
		binary.LittleEndian.PutUint16([0:], uint16(serialCookie))
		 += 2
		binary.LittleEndian.PutUint16([2:], uint16(len(.keys)-1))
		 += 2
		// compute isRun bitmap without temporary allocation
		var  = [ : +]
		for ,  := range .containers {
			switch .(type) {
			case *runContainer16:
				[/8] |= 1 << (uint() % 8)
			}
		}
		 += 
	} else {
		binary.LittleEndian.PutUint32([0:], uint32(serialCookieNoRunContainer))
		 += 4
		binary.LittleEndian.PutUint32([4:], uint32(len(.keys)))
		 += 4
	}

	// descriptive header
	for ,  := range .keys {
		binary.LittleEndian.PutUint16([:], )
		 += 2
		 := .containers[]
		binary.LittleEndian.PutUint16([:], uint16(.getCardinality()-1))
		 += 2
	}

	 := int64( + 4*len(.keys))
	if ! || (len(.keys) >= noOffsetThreshold) {
		// offset header
		for ,  := range .containers {
			binary.LittleEndian.PutUint32([:], uint32())
			 += 4
			switch rc := .(type) {
			case *runContainer16:
				 += 2 + int64(len(.iv))*4
			default:
				 += int64(getSizeInBytesFromCardinality(.getCardinality()))
			}
		}
	}

	,  := .Write([:])
	if  != nil {
		return , 
	}
	 += int64()

	for ,  := range .containers {
		,  := .writeTo()
		if  != nil {
			return , 
		}
		 += int64()
	}
	return , nil
}

// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
func ( *roaringArray) () ([]byte, error) {
	var  bytes.Buffer
	,  := .writeTo(&)
	return .Bytes(), 
}

// Reads a serialized roaringArray from a byte slice.
func ( *roaringArray) ( internal.ByteInput,  ...byte) (int64, error) {
	var  uint32
	var  error
	if len() > 0 && len() != 4 {
		return int64(len()), fmt.Errorf("error in roaringArray.readFrom: could not read initial cookie: incorrect size of cookie header")
	}
	if len() == 4 {
		 = binary.LittleEndian.Uint32()
	} else {
		,  = .ReadUInt32()
		if  != nil {
			return .GetReadBytes(), fmt.Errorf("error in roaringArray.readFrom: could not read initial cookie: %s", )
		}
	}
	// If NextReturnsSafeSlice is false, then willNeedCopyOnWrite should be true
	 := !.NextReturnsSafeSlice()

	var  uint32
	var  []byte

	if &0x0000FFFF == serialCookie {
		 = uint32(>>16 + 1)
		// create is-run-container bitmap
		 := (int() + 7) / 8
		,  = .Next()

		if  != nil {
			return .GetReadBytes(), fmt.Errorf("malformed bitmap, failed to read is-run bitmap, got: %s", )
		}
	} else if  == serialCookieNoRunContainer {
		,  = .ReadUInt32()
		if  != nil {
			return .GetReadBytes(), fmt.Errorf("malformed bitmap, failed to read a bitmap size: %s", )
		}
	} else {
		return .GetReadBytes(), fmt.Errorf("error in roaringArray.readFrom: did not find expected serialCookie in header")
	}

	if  > (1 << 16) {
		return .GetReadBytes(), fmt.Errorf("it is logically impossible to have more than (1<<16) containers")
	}

	// descriptive header
	,  := .Next(2 * 2 * int())

	if  != nil {
		return .GetReadBytes(), fmt.Errorf("failed to read descriptive header: %s", )
	}

	 := byteSliceAsUint16Slice()

	if  == nil ||  >= noOffsetThreshold {
		if  := .SkipBytes(int() * 4);  != nil {
			return .GetReadBytes(), fmt.Errorf("failed to skip bytes: %s", )
		}
	}

	// Allocate slices upfront as number of containers is known
	if cap(.containers) >= int() {
		.containers = .containers[:]
	} else {
		.containers = make([]container, )
	}

	if cap(.keys) >= int() {
		.keys = .keys[:]
	} else {
		.keys = make([]uint16, )
	}

	if cap(.needCopyOnWrite) >= int() {
		.needCopyOnWrite = .needCopyOnWrite[:]
	} else {
		.needCopyOnWrite = make([]bool, )
	}

	for  := uint32(0);  < ; ++ {
		 := [2*]
		 := int([2*+1]) + 1
		.keys[] = 
		.needCopyOnWrite[] = 

		if  != nil && [/8]&(1<<(%8)) != 0 {
			// run container
			,  := .ReadUInt16()

			if  != nil {
				return 0, fmt.Errorf("failed to read runtime container size: %s", )
			}

			,  := .Next(int() * 4)

			if  != nil {
				return .GetReadBytes(), fmt.Errorf("failed to read runtime container content: %s", )
			}

			 := runContainer16{
				iv: byteSliceAsInterval16Slice(),
			}

			.containers[] = &
		} else if  > arrayDefaultMaxSize {
			// bitmap container
			,  := .Next(arrayDefaultMaxSize * 2)

			if  != nil {
				return .GetReadBytes(), fmt.Errorf("failed to read bitmap container: %s", )
			}

			 := bitmapContainer{
				cardinality: ,
				bitmap:      byteSliceAsUint64Slice(),
			}

			.containers[] = &
		} else {
			// array container
			,  := .Next( * 2)

			if  != nil {
				return .GetReadBytes(), fmt.Errorf("failed to read array container: %s", )
			}

			 := arrayContainer{
				byteSliceAsUint16Slice(),
			}

			.containers[] = &
		}
	}

	return .GetReadBytes(), nil
}

func ( *roaringArray) () bool {
	for ,  := range .containers {
		switch .(type) {
		case *runContainer16:
			return true
		}
	}
	return false
}

func ( *roaringArray) ( uint16,  int) int {
	 :=  + 1

	if  >= len(.keys) || .keys[] >=  {
		return 
	}

	 := 1

	for + < len(.keys) && .keys[+] <  {
		 *= 2
	}
	var  int
	if + < len(.keys) {
		 =  + 
	} else {
		 = len(.keys) - 1
	}

	if .keys[] ==  {
		return 
	}

	if .keys[] <  {
		// means
		// array
		// has no
		// item
		// >= min
		// pos = array.length;
		return len(.keys)
	}

	// we know that the next-smallest span was too small
	 += ( >> 1)

	 := 0
	for +1 !=  {
		 = ( + ) >> 1
		if .keys[] ==  {
			return 
		} else if .keys[] <  {
			 = 
		} else {
			 = 
		}
	}
	return 
}

func ( *roaringArray) () {
	for  := range .needCopyOnWrite {
		.needCopyOnWrite[] = true
	}
}

func ( *roaringArray) ( int) bool {
	return .needCopyOnWrite[]
}

func ( *roaringArray) ( int) {
	.needCopyOnWrite[] = true
}